﻿using System;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Compression;
using System.Text;

namespace CommonUtils
{
    /// <summary>
    /// 压缩工具
    /// </summary>
    public static class ZipUtil
    {
        #region zip
        /// <summary>
        /// 获取压缩包中的文件
        /// </summary>
        public static ReadOnlyCollection<ZipArchiveEntry> GetFiles(string path, Encoding nameEncoding = null)
        => ZipFile.Open(path, ZipArchiveMode.Read, nameEncoding.NotNull()).Entries;

        /// <summary>
        /// 获取压缩包中的文件
        /// </summary>
        public static ReadOnlyCollection<ZipArchiveEntry> GetFiles(Stream stream, Encoding nameEncoding = null)
        {
            try
            {
                return new ZipArchive(stream, ZipArchiveMode.Read, false, nameEncoding.NotNull()).Entries;
            }
            catch (Exception ex)
            {
                ex.Message.Print();
                return null;
            }
        }

        /// <summary>
        /// 创建压缩文件
        /// </summary>
        public static void Create(string folder, string path, bool includeBaseDirectory = true, CompressionLevel compressionLevel = CompressionLevel.Fastest)
        => ZipFile.CreateFromDirectory(folder, path, compressionLevel, includeBaseDirectory);

        /// <summary>
        /// 创建压缩文件
        /// </summary>
        public static Stream CreateStream(Map<string, Stream> streams)
        {
            try
            {
                var memory = new MemoryStream();
                var zip = new ZipArchive(memory, ZipArchiveMode.Create, true);
                foreach (var nameStream in streams)
                {
                    var entry = zip.CreateEntry(nameStream.Key);
                    entry.Open().Load(nameStream.Value, true, true);
                }
                //这里不释放，文件下载完会出错
                zip.Dispose();
                memory.Seek();
                return memory;
            }
            catch (Exception ex)
            {
                LogUtil.Record(ex);
                return default;
            }
        }

        public static Stream Create(Map<string, Stream> streams)
        => CreateStream(streams);

        /// <summary>
        /// 创建压缩文件
        /// </summary>
        public static Stream CreateZip(this DirectoryInfo folder, bool includeBaseDirectory = true, CompressionLevel compressionLevel = CompressionLevel.Fastest)
        {
            var memory = new MemoryStream();
            var zip = new ZipArchive(memory, ZipArchiveMode.Create, true);

            //添加文件
            foreach (var file in folder.GetAllFiles())
            {
                var entryName = folder.GetSubRelativePath(file);
                if (includeBaseDirectory)
                    entryName = folder.Name.Combine(entryName);
                var entry = zip.CreateEntry(entryName, compressionLevel);
                entry.Open().LoadFile(file.FullName, true);
            }

            //空文件夹也要保留
            foreach (var subFolder in folder.GetEmptyFolders())
            {
                var entryName = folder.GetSubRelativePath(subFolder);
                if (includeBaseDirectory)
                    entryName = folder.Name.Combine(entryName);
                zip.CreateEntry(entryName, compressionLevel);
            }

            //这里不释放，文件下载结束时,会报错
            zip.Dispose();
            memory.Seek();
            return memory;
        }

        /// <summary>
        /// 创建压缩文件
        /// </summary>
        public static void CreateZip(this DirectoryInfo folder, string file, bool includeBaseDirectory = true, CompressionLevel compressionLevel = CompressionLevel.Fastest)
        => Create(folder.FullName, file, includeBaseDirectory, compressionLevel);
        #endregion

        #region 压缩/解压 GZipStream
        //GZipStream与初始化的Stream会关联Close,所以MemoryStream不用关，外部关闭GZipStream即可
        //GZipStream的CanSeek为False，不支持Position和Length

        /// <summary>
        /// 解压
        /// </summary>
        public static byte[] GZipDecompress(this byte[] bytes)
        => new GZipStream(new MemoryStream(bytes), CompressionMode.Decompress).ToBytes();

        /// <summary>
        /// 解压(此方法代替Unzip().ToStream(),少一步字节遍历)
        /// </summary>
        public static Stream GZipDecompressStream(this byte[] bytes)
        => new GZipStream(new MemoryStream(bytes), CompressionMode.Decompress);

        /// <summary>
        /// 解压
        /// </summary>
        public static Stream GZipDecompress(this Stream stream)
        => new GZipStream(stream, CompressionMode.Decompress);

        /// <summary>
        /// 解压
        /// </summary>
        public static byte[] GZipDecompressBytes(this Stream stream)
        => new GZipStream(stream, CompressionMode.Decompress).ToBytes();

        /// <summary>
        /// 获取解压后的UTF8编码的字符串
        /// </summary>
        public static string GZipDecompressString(this byte[] bytes, Encoding encoding = null)
        => new GZipStream(new MemoryStream(bytes), CompressionMode.Decompress).GetString(encoding);

        /// <summary>
        /// 获取解压后的UTF8编码的字符串
        /// </summary>
        public static string GZipDecompressString(this Stream stream, Encoding encoding = null)
        => new GZipStream(stream, CompressionMode.Decompress).GetString(encoding);
        #endregion
    }
}
